﻿/******************************************************************
 *Company: http://www.xiaomutech.com/
 *fileName : qwidgetbase.cpp --- QWidgetBase
 *Auth       : yhni (QQ:393320854)
 *Create    : 2022/9/9
 *Description   :
 *Histroy:
 *<Auth>    <Date>        <Ver>        <Content>
 *         2022/9/9
 *******************************************************************/
#include "qwidgetbase.h"

#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
#include <QWindow>
#include <QDebug>

#include <QKeyEvent>
#include <QMouseEvent>
#include <QStyleOption>
#include <QPainter>

#ifdef Q_OS_WIN
#include <dwmapi.h>
#include <windows.h>
#include <windowsx.h>
#endif

QWidgetBase::QWidgetBase(QWidget *parent) : QWidget(parent)
{
    setAttribute(Qt::WA_StyledBackground, true);
    setWidgetBorderless();
}

QWidgetBase::~QWidgetBase()
{
}


void QWidgetBase::setWidgetBorderless()
{
    this->setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
#ifdef Q_OS_WIN
#ifndef _MSC_VER
    DwmEnableComposition(DWM_EC_ENABLECOMPOSITION); // windows7 need disable.
    HWND hwnd = reinterpret_cast<HWND>(winId());
    DWORD style = GetWindowLong(hwnd, GWL_STYLE);
    SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);

    // add window shadow.
    const MARGINS shadow = { 1, 1, 1, 1 };
    DwmExtendFrameIntoClientArea(HWND(winId()), &shadow);
#endif
#endif
}

#ifndef _MSC_VER
bool QWidgetBase::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
#ifdef Q_OS_WIN
    if (eventType != "windows_generic_MSG")
        return false;

    MSG* msg = static_cast<MSG*>(message);
    QWidget* widget = QWidget::find(reinterpret_cast<WId>(msg->hwnd));
    if (!widget)
        return false;

    switch (msg->message) {

    case WM_NCCALCSIZE: {
        *result = 0;
        return true;
    }

    case WM_NCHITTEST:
    {
        RECT winrect;
        GetWindowRect(HWND(winId()), &winrect);

        int x = GET_X_LPARAM(msg->lParam);
        int y = GET_Y_LPARAM(msg->lParam);

        QScreen *screen = windowHandle()->screen();
        m_dpiScale = screen->devicePixelRatio();
        if (windowState() == Qt::WindowFullScreen) {
            *result = HTCLIENT;
            return true;
        }

        const LONG border_width = 5;
        bool m_bResizeable = true;
        if (m_bResizeable)
        {
            bool resizeWidth = minimumWidth() != maximumWidth();
            bool resizeHeight = minimumHeight() != maximumHeight();

            if (resizeWidth)
            {
                //left border
                if (x >= winrect.left && x < winrect.left + border_width)
                {
                    *result = HTLEFT;
                }
                //right border
                if (x < winrect.right && x >= winrect.right - border_width)
                {
                    *result = HTRIGHT;
                }
            }
            if (resizeHeight)
            {
                //bottom border
                if (y < winrect.bottom && y >= winrect.bottom - border_width)
                {
                    *result = HTBOTTOM;
                }
                //top border
                if (y >= winrect.top && y < winrect.top + border_width)
                {
                    *result = HTTOP;
                }
            }
            if (resizeWidth && resizeHeight)
            {
                //bottom left corner
                if (x >= winrect.left && x < winrect.left + border_width &&
                    y < winrect.bottom && y >= winrect.bottom - border_width)
                {
                    *result = HTBOTTOMLEFT;
                }
                //bottom right corner
                if (x < winrect.right && x >= winrect.right - border_width &&
                    y < winrect.bottom && y >= winrect.bottom - border_width)
                {
                    *result = HTBOTTOMRIGHT;
                }
                //top left corner
                if (x >= winrect.left && x < winrect.left + border_width &&
                    y >= winrect.top && y < winrect.top + border_width)
                {
                    *result = HTTOPLEFT;
                }
                //top right corner
                if (x < winrect.right && x >= winrect.right - border_width &&
                    y >= winrect.top && y < winrect.top + border_width)
                {
                    *result = HTTOPRIGHT;
                }
            }
        }
        if (0 != *result) return true;
        *result = HTCLIENT;

        double dpr = m_dpiScale;
        auto ax = (x - winrect.left) / dpr;
        auto ay = (y - winrect.top) / dpr;
        QPoint pos(ax, ay);

        QWidget* tempWidget = this->childAt(pos);
        if (tempWidget == NULL)
        {
            *result = HTCAPTION;
            return true;
        }
        else {
            if (ay < 60) {
                if (tempWidget->objectName() == "widgetTitle") {
                    *result = HTCAPTION;
                    return true;
                }
            }
        }
        return true;
    }

    case WM_GETMINMAXINFO: {
        if (::IsZoomed(msg->hwnd)) {
            RECT frame = { 0, 0, 0, 0 };
            AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0);
            frame.left = abs(frame.left);
            frame.top = abs(frame.bottom);
            widget->setContentsMargins(int(frame.left / m_dpiScale), int(frame.top / m_dpiScale), int(frame.right / m_dpiScale), int(frame.bottom / m_dpiScale));
        }
        else {
            widget->setContentsMargins(0, 0, 0, 0);
        }

        *result = ::DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
        return true;
    }
        break;

    default:
        break;
    }
#endif

    return QWidget::nativeEvent(eventType, message, result);
}
#endif

void QWidgetBase::changeEvent(QEvent* e)
{
    if (e->type() == QEvent::WindowStateChange)
    {
        QWindowStateChangeEvent* event = static_cast<QWindowStateChangeEvent*>(e);

        if (event->oldState() & Qt::WindowMinimized)
        {

        }

        if (event->oldState() == Qt::WindowMaximized && this->windowState() == Qt::WindowNoState)
        {

        }
        else if (event->oldState() == Qt::WindowNoState && this->windowState() == Qt::WindowMaximized)
        {

        }
    }
}

void QWidgetBase::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
